// Game.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Engine/Map.hpp>
#include <Engine/MapRenderer.hpp>
#include <Engine/TerrainMaterialManager.hpp>
#include <Engine/UnitEntityManager.hpp>
#include <engine/CamerManager.hpp>
#include <engine/LightManager.hpp>
#include <engine/World.hpp>
#include <engine/WorldRenderer.hpp>
#include "GameFramework.hpp"

int main(int argc, char* argv[])
{
#if defined(_DEBUG)
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
	// Create root object
	Ogre::Root* root = new Ogre::Root;
	try
	{
		boost::filesystem::path wrk_path = boost::filesystem::initial_path();
		//  Load config
		Ogre::ConfigFile cf;
		cf.load("resources.cfg");
		// Go through all sections and settings in the file
		Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
		Ogre::String secName, typeName, archName;
		while (seci.hasMoreElements())
		{
			secName = seci.peekNextKey();
			Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
			Ogre::ConfigFile::SettingsMultiMap::iterator i;
			for (i = settings->begin(); i != settings->end(); ++i)
			{
				typeName = i->first;
				archName = i->second;
				Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
					archName, typeName, secName);
			}
		}
		// Try to load config, and if failed, show config dialog
		if(root->restoreConfig() || root->showConfigDialog())
		{
			// Create main window
			Ogre::RenderWindow* p_window = root->initialise(true, "High Explosive");
			// Get window metrics
			unsigned int width, height, depth;
			int top, left;
			p_window->getMetrics(width, height, depth, left, top);
			Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
			// Create the SceneManager
			Ogre::SceneManager* p_scene_manager = root->createSceneManager(Ogre::ST_GENERIC); 
			// Create the camera
			he::CameraManager camera_manager(*p_scene_manager, *p_window, "MainCam");
			camera_manager.set_camera_position(width / 40.f, height / 40.f, 5);
			// Create a light
			he::LightManager ligh_manager(*p_scene_manager);
			// OIS input handling 
			OIS::ParamList pl;
			size_t windowHnd = 0;
			std::ostringstream windowHndStr;
			//tell OIS about the Ogre window
			p_window->getCustomAttribute("WINDOW", &windowHnd);
			windowHndStr << windowHnd;
			pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
			//setup the manager, keyboard and mouse to handle input
			OIS::InputManager* inputManager = OIS::InputManager::createInputSystem(pl);
			OIS::Keyboard* keyboard = static_cast<OIS::Keyboard*>(inputManager->createInputObject(OIS::OISKeyboard, true));
			OIS::Mouse*	mouse = static_cast<OIS::Mouse*>(inputManager->createInputObject(OIS::OISMouse, true));
			char key_state[256], key_state_old[256];
			//tell OIS about the window's dimensions
			const OIS::MouseState &ms = mouse->getMouseState();
			ms.width = width;
			ms.height = height;
			CEGUI::OgreRenderer *p_gui_render = &CEGUI::OgreRenderer::bootstrapSystem();
			CEGUI::Imageset::setDefaultResourceGroup("Imagesets");
			CEGUI::Font::setDefaultResourceGroup("Fonts");
//			CEGUI::Scheme::setDefaultResourceGroup("Schemes");
//			CEGUI::WidgetLookManager::setDefaultResourceGroup("LookNFeel");
//			CEGUI::WindowManager::setDefaultResourceGroup("Layouts");
//			CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme");
//			CEGUI::System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
			// Open map
			std::ifstream map_txt("map.txt");
			// Create world
			he::World world(he::Map::create_map(map_txt), "");
			// World renderer
			he::WorldRenderer world_renderer(*p_scene_manager, world);
			// Create entity from mesh and attach it to a scene node.
			// Create timer
			Ogre::Timer timer;
			bool run = true;
			float last_time = 0;
			// ----
//			p_camera->setPolygonMode(Ogre::PM_WIREFRAME);
			// ----
			while(run)
			{
				DWORD const start = GetTickCount();

				Ogre::WindowEventUtilities::messagePump();
				// Update the input devices
				keyboard->capture();
				mouse->capture();
				// Exit if key KC_ESCAPE pressed 
				if(keyboard->isKeyDown(OIS::KC_ESCAPE)) 
					run = false;
				// Get state of all keys
				keyboard->copyKeyStates(key_state);
				// Switch camera
				if(key_state_old[OIS::KC_C] == 1 && key_state[OIS::KC_C] == 0)
					camera_manager.switch_debug_camera();
				{
				}
				// Need to save old state
				std::copy(key_state, key_state + 256, key_state_old);
				// Update camera position
				{
					Ogre::Vector3 translate_camera = Ogre::Vector3::ZERO;
					if(keyboard->isKeyDown(OIS::KC_UP))
						translate_camera = Ogre::Vector3(0, 0, -1);
					else if(keyboard->isKeyDown(OIS::KC_DOWN))
						translate_camera = Ogre::Vector3(0, 0, 1);
					else if(keyboard->isKeyDown(OIS::KC_LEFT))
						translate_camera = Ogre::Vector3(-1, 0, 0);
					else if(keyboard->isKeyDown(OIS::KC_RIGHT))
						translate_camera = Ogre::Vector3(1, 0, 0);
					// Only if need to move
					if(translate_camera != Ogre::Vector3::ZERO)
						camera_manager.move_main_camera_relative(translate_camera);
				}
				// Render sprite

				// Let the framework update data
				float new_time = timer.getMilliseconds() / 1000.f;
				world_renderer.update(delta);
				last_time = new_time;
//				std::cout << "Total time: " << timer.getMilliseconds() / 1000.f << std::endl;
				// Render frame
				root->renderOneFrame();


				DWORD const end = GetTickCount();
				auto const time_diff = end - start;
				if(time_diff < 33)
					Sleep(33 - time_diff);
			}
			CEGUI::OgreRenderer::destroySystem();
			inputManager->destroyInputObject(mouse);
			inputManager->destroyInputObject(keyboard);
			OIS::InputManager::destroyInputSystem(inputManager);
		}
	}
	catch(std::exception const &e)
	{
		std::cout << "Exception caught: " << e.what() << std::endl;
	}
	//Ogre
	delete root;


	return 0;
}

